home *** CD-ROM | disk | FTP | other *** search
- PAGE 59, 132
-
- TITLE MSXModem -- Send and receive files using the XMODEM protocol
-
- ; Update 8 Jan 86
-
- IF1
- %OUT >> Starting pass 1
- ELSE
- %OUT >> Starting pass 2
- ENDIF
-
- PUBLIC XSend, XReceive
-
- INCLUDE MsDefs.H
-
- DataS SEGMENT PUBLIC 'DataS'
-
- EXTRN Count:WORD, Pack:BYTE, OFilSz:WORD, TFilSz:WORD, PortVal:WORD
-
- ; Static data
-
- ErMs31 DB '? File not found',cr,lf,'$'
- ErMs32 DB "? Can't create file",cr,lf,'$'
- No_data_in_file DB '? File is empty', Cr, Lf, '$'
- No_initiating_NAK DB 'Timeout waiting for receiver to start$'
- Too_many_retries DB 'Too many retries$'
- XM_send_status DB cr,' XMODEM send: Waiting for receiver to start$'
- XM_receive_status DB cr,' XMODEM receive: Starting$'
- In_progress DB 'In progress$'
- Completed DB 'Completed$'
- Failed DB 'Failed$'
- File_help DB ' File specification with optional path name$'
-
- ; Writable data
-
- EVEN
- Tally DW 0 ; Counter for checksum
- Filename_ptr DW 0 ; Pointer to filename from SPath routine
- Handle DW 0 ; File handle for FT file
- File_size DD 0 ; File size
- Buffer_ptr DW 0 ; Pointer into file buffer
- Buffer_count DW 0 ; Count of characters in buffer
- HrMn DW 0 ; Place to save hours and minutes
- ScHn DW 0 ; Place to save seconds and hundredths
- TFile DB 100 DUP (?) ; Place to store file name
- Buffer DB 1024 DUP (?) ; File I/O buffer
- Abort_flag DB 0 ; Flag that ^C was hit
- EOT_flag DB 0 ; Flag that we received a valid EOT signal
- Timeout DB 0 ; Number of seconds to allow
-
- DataS ENDS
-
- Code SEGMENT PUBLIC
-
- EXTRN Comnd:NEAR, SPath:NEAR, Init:NEAR, Close_transfer_screen:NEAR
- EXTRN Show_error:NEAR, Show_retries:NEAR, Show_status:NEAR, PerPr:NEAR
- EXTRN SerIni:NEAR, Nout:NEAR, RRInit:NEAR, Init:NEAR, Show_packets:NEAR
- EXTRN ClrFln:NEAR, Write_to_standard_output:NEAR, KbPr:NEAR, PrtChr:NEAR
- EXTRN Beep:NEAR, Say_aborted:NEAR, OutChr:NEAR, ClrBuf:NEAR, SerRst:NEAR
- EXTRN EOT_bells:NEAR
-
- ASSUME cs:Code, ds:DataS, es:DataS
-
-
- ; XReceive -- XMODEM receive routine, called at command level
-
- XReceive PROC
-
- mov ah, CMTXT ; Read in a line of text
- mov bx, OFFSET TFile ; Temp area for text, max 100 chars
- mov dx, OFFSET File_help ; File specification with optional path name
- call Comnd ; Do it
- jmp RSkp
-
- mov si, OFFSET TFile ; Point to start of user input
- mov bl, ah ; Copy length to bl
- sub bh, bh ; Clear high half
- mov BYTE PTR [si+bx], 0 ; Make it ASCIZ
-
- mov ax, (CREATE2*256) + 0 ; DOS 2.0 file create call
- sub cx, cx ; No special attributes
- mov dx, OFFSET TFile ; Point to name again
- int Dos
- jnc XRE_3 ; Create ok, keep going
-
- XRE_2: mov ah, PrStr ; Code to type a message
- mov dx, OFFSET ErMs32 ; ? Can't create file
- int Dos ; Type it
-
- jmp RSkp
-
- XRE_3: mov Buffer_count, 0 ; Clear count of chars in buffer
- mov Buffer_ptr, OFFSET Buffer ; Set up initial buffer pointer
-
- mov Handle, ax ; Save file descriptor
- mov OFilSz, 0 ; Flag no percentages on this
-
- call SerRst ; Unhook serial interrupt first just-in-case
- call SerIni ; Set up serial port as required
-
- call RRInit ; Set up counters
- call Init ; Set up screen for file transfer
-
- mov dx, OFFSET XM_receive_status ; "XMODEM receive: Starting"
- call Show_status ; Display status
-
- mov Pack.NumRtr, 0 ; Clear the retry count
- call Show_retries ; then display it
-
- call ClrFln ; Clear filename and position us there
- mov dx, OFFSET TFile ; Give him the filename pointer
- call Write_to_standard_output ; Use common routine to type filename
-
- mov bx, PortVal ; Port structure
- mov al, [bx].floflg ; Save current flow control setting
- push ax
- mov [bx].floflg, 0 ; Turn it off for XMODEM
-
- call Do_XMODEM_receive ; Use other routine to do the work
-
- call EOT_bells ; Make an optional noise
-
- mov bx, PortVal ; Port structure
- pop ax
- mov [bx].floflg, al ; Restore it to what it was
-
- call Close_transfer_screen ; Make screen go normal again
-
- mov ah, CLOSE2 ; Code to close a file
- mov bx, Handle ; The file handle
- int Dos ; Close the file
-
- cmp Abort_flag, 0 ; Did we abort this transfer?
- je XRE_9 ; No
-
- mov ah, 41h ; Code to unlink (delete) a file
- mov dx, OFFSET TFile ; Filename used to create file
- int Dos ; Delete the file
-
- PUBLIC XRE_9
-
- XRE_9: jmp RSkp ; Done here
-
- XReceive ENDP
-
-
- ; XSend -- XMODEM send routine, called at command level
-
- XSend PROC
-
- mov ah, CMTXT ; Read in a line of text
- mov bx, OFFSET TFile ; Temp area for text, max 100 chars
- mov dx, OFFSET File_help ; File specification with optional path name
- call Comnd ; Do it
- jmp RSkp
-
- mov si, OFFSET TFile ; Point to start of user input
- mov bl, ah ; Copy length to bl
- sub bh, bh ; Clear high half
- mov BYTE PTR [si+bx], 0 ; Make it ASCIZ
-
- mov ax, si ; Point to name again
- call SPath ; Is it around?
- jc XSE_2 ; No, go complain
-
- mov Filename_ptr, ax ; Save pointer to filename for later
- mov dx, ax ; Point to name from SPath
- mov ax, (Open2*256) + 0 ; DOS 2.0 open call for read
- int Dos
- jnc XSE_3 ; Open ok, keep going
-
- XSE_2: mov ah, PrStr ; Code to type a message
- mov dx, OFFSET ErMs31 ; ? File not found
- int Dos ; Type it
-
- jmp RSkp
-
- XSE_3: mov Handle, ax ; Save file descriptor
- mov bx, ax ; Need descriptor here
-
- mov ax, (LSeek*256) + 2 ; Seek 0 bytes from end
- sub cx, cx
- sub dx, dx
- int Dos
-
- mov WORD PTR File_size, ax ; Store length
- mov WORD PTR File_size + 2, dx ; (doubleword)
-
- mov cx, ax ; Copy low order part to cx
- or cx, dx ; Merge the two words
- jnz XSE_4 ; There is at least one character
-
- mov ah, PrStr ; Code to type a message
- mov dx, OFFSET No_data_in_file ; ? File is empty
- int Dos ; Type the message
-
- jmp RSkp ; Give up
-
- XSE_4: mov bx, 100 ; Get a 100 into bx
- div bx ; Convert file size for percentage calculation
- mov OFilSz, ax ; Save it for PerPr
-
- mov ax, (LSeek*256) + 0 ; Seek back to the beginning
- mov bx, Handle ; Get back the file handle
- sub cx, cx
- sub dx, dx
- int Dos
-
- call Read_a_bufferfull ; Use other routine to load the buffer
-
- call SerRst ; Unhook serial interrupt first just-in-case
- call SerIni ; Set up serial port as required
-
- call RRInit ; Set up counters
- call Init ; Set up screen for file transfer
-
- mov dx, OFFSET XM_send_status ; "XMODEM send: Waiting for ..."
- call Show_status ; Display status
-
- mov Pack.NumRtr, 0 ; Clear the retry count
- call Show_retries ; then display it
-
- call ClrFln ; Clear filename and position us there
- mov dx, Filename_ptr ; Give him the filename pointer
- call Write_to_standard_output ; Use common routine to type filename
-
- mov bx, PortVal ; Port structure
- mov al, [bx].floflg ; Save current flow control setting
- push ax
- mov [bx].floflg, 0 ; Turn it off for XMODEM
-
- call Do_XMODEM_send ; Use other routine to do the work
-
- call EOT_bells ; Make an optional noise
-
- mov bx, PortVal ; Port structure
- pop ax
- mov [bx].floflg, al ; Restore it to what it was
-
- call Close_transfer_screen ; Make screen go normal again
-
- mov ah, CLOSE2 ; Code to close a file
- mov bx, Handle ; The file handle
- int Dos ; Close the file
-
- jmp RSkp ; Done here
-
- XSend ENDP
-
-
- PUBLIC Write_a_bufferfull
-
- ; Write_a_bufferfull -- Write to HANDLE from BUFFER
-
- Write_a_bufferfull PROC
-
- cmp Buffer_count, 0 ; Are chars to dump?
- jz WAB_1 ; Nothing to do, just exit
-
- mov ah, WRITEF2 ; DOS 2.0 file handle write
- mov bx, Handle ; File handle to use
- mov cx, Buffer_count ; Amount of stuff in buffer
- mov dx, OFFSET Buffer ; Ptr to buffer
- int Dos ; Write a buffer full
-
- mov Buffer_count, 0 ; Clear count of chars in buffer
-
- WAB_1: mov Buffer_ptr, OFFSET Buffer ; Set up initial buffer pointer
- ret ; Done here
-
- Write_a_bufferfull ENDP
-
-
- ; Read_a_bufferfull -- Read from HANDLE into BUFFER
-
- Read_a_bufferfull PROC
-
- mov si, OFFSET Buffer ; Ptr to start of buffer
- mov di, OFFSET Buffer + 1 ; Next byte
- mov cx, (SIZE Buffer)-1 ; How many to copy
- mov BYTE PTR [si], CtlZ ; Clear first element of array with control-Z
- rep movsb ; Clear rest of array
-
- mov ah, ReadF2 ; DOS 2.0 file handle read
- mov bx, Handle ; File handle to use
- mov cx, SIZE Buffer ; Size of buffer
- mov dx, OFFSET Buffer ; Ptr to buffer
- int Dos ; Read a buffer full, or whatever we can get
-
- mov Buffer_count, ax ; Store number of chars read
- sub WORD PTR File_size, ax ; Account for what we have just read
- sbb WORD PTR File_size + 2, 0 ; Do high order half also
- mov Buffer_ptr, OFFSET Buffer ; Set up initial buffer pointer
- ret ; Done here
-
- Read_a_bufferfull ENDP
-
-
- ; Do_XMODEM_receive -- Worker XMODEM file receive routine
-
- Do_XMODEM_receive PROC
-
- call ClrBuf ; Flush any chars already received
-
- mov EOT_flag, 0 ; Clear this flag
- mov Pack.NumPkt, 0 ; Clear count of transmitted packets
- mov Pack.PktNum, 1 ; XMODEM starts with packet number 1
- mov TFilSz, 0 ; Clear out transfered file size ...
- mov TFilSz + 2, 0 ; ... low half too (this is backwards)
-
- mov ah, ASCII_NAK ; Load up the char to send
- call OutChr ; Send it once
- nop
- nop
- nop
-
- DXR_1: mov Pack.NumTry, 0 ; Clear this counter
- mov dx, OFFSET In_progress ; "XMODEM receive: In progress"
- call Show_status ; Display status
-
- DXR_2: call Receive_a_packet ; Receive a packet
- jnc DXR_4 ; Got a packet with no timeout or error
-
- cmp Abort_flag, 0 ; Aborted?
- jz DXR_No_abort ; No
-
- mov dx, OFFSET Failed ; Say transfer bombed
- jmp Show_status
-
- DXR_No_abort:
- inc Pack.NumRtr ; Bump global count
- call Show_retries ; Show the user
-
- inc Pack.NumTry ; Bump the count of retries on this packet
- cmp Pack.NumTry, 10 ; Hit 10 failures yet?
- jl DXR_2 ; No, keep going
-
- mov dx, OFFSET Failed
- call Show_status
-
- mov dx, OFFSET Too_many_retries ; Too many retries
- jmp Show_error ; Complain on-screen, ret from there
-
- DXR_4: cmp EOT_flag, 0 ; Receive an EOT?
- jne DXR_EOT ; Yes, ACK it and close file
-
- mov Pack.NumTry, 0 ; Clear per-packet error counter
- inc Pack.PktNum ; Advance to next packet number
- inc Pack.NumPkt ; Bump the number of packets
- call Show_packets ; Display the number of packets
-
- add TFilSz + 2, 128 ; Bump amount transmitted
- adc TFilSz, 0 ; and high half (done wrong for compatibility)
-
- call KbPr ; Show how we're doing ...
-
- add Buffer_ptr, 128 ; Advance this ptr
- add Buffer_count, 128 ; This counter too
-
- cmp Buffer_count, SIZE Buffer ; Is the buffer now full?
- jl DXR_2 ; Still room, get another packet
-
-
- %OUT >> About half way through source file
-
-
- call Write_a_bufferfull ; Dump out the buffer
- jmp DXR_2 ; Go do another packet
-
- DXR_EOT:
- call Write_a_bufferfull ; Dump out the buffer
- mov dx, OFFSET Completed ; "XMODEM receive: Completed"
- jmp Show_status ; Display status and go home
-
- Do_XMODEM_receive ENDP
-
-
- ; Do_XMODEM_send -- Worker XMODEM file send routine
-
- Do_XMODEM_send PROC
-
- call ClrBuf ; Flush any chars already received
-
- mov Pack.NumPkt, 0 ; Clear count of transmitted packets
- mov Pack.PktNum, 1 ; XMODEM starts with packet number 1
- mov TFilSz, 0 ; Clear out transfered file size ...
- mov TFilSz + 2, 0 ; ... low half too (this is backwards)
- call Wait_for_NAK ; Give receiver time to start up and NAK us
- jnc DXS_1 ; We are OK
-
- ret ; We never got one
-
- DXS_1: mov Pack.NumTry, 0 ; Clear this counter
- mov dx, OFFSET In_progress ; "XMODEM send: In progress"
- call Show_status ; Display status
-
- DXS_2: call Send_a_packet ; Send a packet
- call Wait_for_ACK ; Get an ACK if we can, fail on timeout or NAK
- jnc DXS_4 ; Got our ACK, move on ...
-
- cmp Abort_flag, 0 ; Aborted?
- jz DXS_No_abort ; No
-
- mov dx, OFFSET Failed ; Say transfer bombed
- jmp Show_status
-
- DXS_No_abort:
- inc Pack.NumRtr ; Bump global count
- call Show_retries ; Show the user
-
- inc Pack.NumTry ; Bump the count of retries on this packet
- cmp Pack.NumTry, 10 ; Hit 10 failures yet?
- jl DXS_2 ; No, keep going
-
- mov dx, OFFSET Failed
- call Show_status
-
- mov dx, OFFSET Too_many_retries ; Too many retries
- jmp Show_error ; Complain on-screen, ret from there
-
- DXS_4: add Buffer_ptr, 128 ; Advance this ptr
- sub Buffer_count, 128 ; Drop this counter
-
- mov Pack.NumTry, 0 ; Clear per-packet error counter
- inc Pack.PktNum ; Advance to next packet number
- inc Pack.NumPkt ; Bump the number of packets
- call Show_packets ; Display the number of packets
-
- add TFilSz + 2, 128 ; Bump amount transmitted
- adc TFilSz, 0 ; and high half (done wrong for compatibility)
-
- call KbPr ; Show how we're doing ...
- call PerPr ; Percentage-wise also
-
- cmp Buffer_count, 0 ; Is the buffer now empty?
- jg DXS_2 ; Not empty, do more data
- jl DXS_Send_EOT ; "Over-empty", Buffer_count wasn't 1024
- ; this go round and we used them all up,
- ; so this must be end-of-file
-
- mov ax, WORD PTR File_size ; Pick up half of file size
- or ax, WORD PTR File_size + 2 ; Merge in other half
- jz DXS_Send_EOT ; No chars to read, close it out
-
- call Read_a_bufferfull ; Load up the buffer
- jmp DXS_2 ; Go do another packet
-
- DXS_Send_EOT:
- mov Pack.NumTry, 0 ; Clear per-packet retry counter
-
- DXS_EOT_loop:
- mov ah, EOT ; Get an ACK
- call OutChr ; Send it out
- nop
- nop
- nop
-
- call Wait_for_ACK ; Wait for ACK, NAK or timeout
- jnc DXS_EOT_1 ; Got our ACK, move on ...
-
- cmp Abort_flag, 0 ; Aborted?
- jz DXS_EOT_no_abort
-
- mov dx, OFFSET Failed ; Say transfer bombed
- jmp Show_status
-
- DXS_EOT_no_abort:
- inc Pack.NumRtr ; Bump global count
- call Show_retries ; Show the user
-
- inc Pack.NumTry ; Bump the count of retries on this packet
- cmp Pack.NumTry, 10 ; Hit 10 failures yet?
- jl DXS_EOT_loop ; No, keep going
-
- mov dx, OFFSET Failed
- call Show_status
-
- mov dx, OFFSET Too_many_retries ; Message
- jmp Show_error ; Complain on-screen, ret from there
-
- DXS_EOT_1:
- mov dx, OFFSET Completed ; "XMODEM send: Completed"
- jmp Show_status ; Display status
-
- Do_XMODEM_send ENDP
-
-
- Wait_for_NAK PROC
-
- mov Abort_flag, 0 ; Clear abort flag
- mov ah, 2Ch ; Code to Get Time
- int Dos ; Get it
-
- inc cl ; Bump the minutes
- cmp cl, 59 ; Too many?
- jbe WFN_doit ; No
-
- sub cl, 60 ; Pull down the minutes
- inc ch ; Bump the hours
-
- WFN_doit:
- mov HrMn, cx ; Save hours and minutes
- mov ScHn, dx ; Save seconds and hundredths
-
- WFN_Loop:
- cmp Count, 0 ; Any characters to read?
- jnz WFN_Got_char ; Found one
-
- mov dl, 0FFh ; Want input mode
- mov ah, DConIO ; Code for direct console input w/o echo
- int Dos ; Get a char if any is there
- jz WFN_No_keyboard ; User hasn't typed anything
-
- cmp al, 3 ; User type ^C?
- jne WFN_Not_Ctrl_C ; No
-
- mov Abort_flag, 0FFh ; Flag the abort
- jmp Say_Aborted ; Standard exit message for ^C
-
- WFN_Not_Ctrl_C:
- or al, al ; Zero?
- jne WFN_Beep ; No
-
- int Dos ; Eat the second part of the funny char
-
- WFN_Beep:
- call Beep ; User hit wrong key, make a noise
-
- WFN_No_keyboard:
- call Carry_if_expired ; See if time has hit yet
- jnc WFN_loop ; Not yet
-
- mov dx, OFFSET Failed
- call Show_status
-
- mov dx, OFFSET No_initiating_NAK
- jmp Show_error ; Timeout, complain and return with carry on
-
- WFN_Got_char:
- call PrtChr ; Pick up the character
- cmp al, ASCII_NAK ; Did we get what we wanted?
- je WFN_Done ; Yes
-
- inc Pack.NumRtr ; Call every noise character a retry
- call Show_retries ; Display it
- jmp WFN_Loop
-
- WFN_Done:
- clc ; Found a NAK, clear the error flag
- ret ; Go home happy
-
- Wait_for_NAK ENDP
-
-
- Wait_for_ACK PROC
-
- mov Abort_flag, 0 ; Clear abort flag
- mov ah, 2Ch ; Code to Get Time
- int Dos ; Get it
-
- inc cl ; Bump the minutes
- cmp cl, 59 ; Too many?
- jbe WFA_doit ; No
-
- sub cl, 60 ; Pull down the minutes
- inc ch ; Bump the hours
-
- WFA_doit:
- mov HrMn, cx ; Save hours and minutes
- mov ScHn, dx ; Save seconds and hundredths
-
- WFA_Loop:
- cmp Count, 0 ; Any characters to read?
- jz WFA_No_char ; None
-
- call PrtChr ; Pick up the character
- cmp al, ACK ; Did we get an ACK?
- jne WFA_Not_ACK ; No
-
- clc ; Clear the error flag
- ret ; Go home happy
-
- WFA_Not_ACK:
- cmp al, ASCII_NAK ; Did we get a NAK?
- jne WFA_Not_NAK ; Yes
-
- stc ; Flag the error
- ret ; Go home
-
- WFA_Not_NAK:
- inc Pack.NumRtr ; Call every noise character a retry
- call Show_retries ; Display it
- jmp WFA_Loop
-
- WFA_No_char:
- mov ah, DConIO ; Code for direct console input w/o echo
- mov dl, 0FFh ; Want input mode
- int Dos ; Get a char if any is there
- jz WFA_No_keyboard ; User hasn't typed anything
-
- cmp al, 3 ; User type ^C?
- jne WFA_Not_Ctrl_C ; No
-
- mov Abort_flag, 0FFh ; Flag the abort
- jmp Say_Aborted ; Standard exit message for ^C
-
- WFA_Not_Ctrl_C:
- or al, al ; Zero?
- jne WFA_Beep ; No
-
- int Dos ; Eat the second part of the funny char
-
- WFA_Beep:
- call Beep ; User hit wrong key, make a noise
-
- WFA_No_keyboard:
- call Carry_if_expired ; See if time has hit yet
- jnc WFA_Loop ; Not yet
-
- ret ; Return with carry set
-
- Wait_for_ACK ENDP
-
-
- ; Routine to set the Carry Flag if the SLEEP timer has expired, clear it if not
-
- Carry_if_expired PROC
-
- mov ah, 2Ch ; Code to Get Time
- int Dos ; Get it
-
- cmp cx, HrMn ; Is the hour/minute too early?
- jb CIE_Not_expired ; Yes
- ja CIE_Expired ; NO!
-
- ; Maybe ...
-
- cmp dx, ScHn ; How about the seconds?
- jb CIE_Not_expired ; Too early
-
- CIE_Expired:
- stc ; Set the carry flag
- ret ; Return
-
- CIE_Not_expired:
- clc ; Clear the carry flag
- ret ; Return
-
- Carry_if_expired ENDP
-
-
- PUBLIC Receive_a_packet
-
- ; Receive_a_packet -- Routine to receive and disassemble an XMODEM data packet
-
- Receive_a_packet PROC
-
- mov Timeout, 10 ; Start with a ten second timeout
- call Get_char ; Get a char or timeout
- jc RAP_empty ; Timeout
- cmp al, SOH ; Proper start?
- je RAP_1 ; Yes
- cmp al, EOT ; EOT?
- jne RAP_err ; No, error
-
- mov EOT_flag, 1 ; Turn on this flag
- jmp SHORT RAP_OK ; Acknowledge it like a packet
-
- RAP_1: mov Timeout, 1 ; Switch to a quicker timeout
- call Get_char ; Get a char or timeout, 1 second
- jc RAP_empty ; Timeout
- cmp al, BYTE PTR Pack.PktNum ; Right packet number?
- jne RAP_err
-
- call Get_char ; Get a char or timeout
- jc RAP_empty ; Timeout
- not al ; Flip the bits
- cmp al, BYTE PTR Pack.PktNum ; Still look right?
- jne RAP_err
-
- mov cx, 128 ; Number of chars to get
- mov di, Buffer_ptr ; Pick up current ptr
- mov Tally, 0 ; Clear counter
-
- RAP_Loop:
- call Get_char ; Get a char or timeout
- jc RAP_empty ; Timeout
-
- stosb ; Lay down the byte
- sub ah, ah ; Clear high half
- add Tally, ax ; Add in the new character
- loop RAP_Loop ; Do 128 characters
-
- call Get_char ; Get a char or timeout
- jc RAP_empty ; Timeout
- cmp al, BYTE PTR Tally ; Does the checksum match?
- jne RAP_err ; No good
-
- RAP_OK: mov ah, ACK ; Code to ACK a good packet
- call OutChr ; Send it out
- nop
- nop
- nop
-
- clc ; No errors, right block number and everything
- ret ; Go home
-
- RAP_err:
- mov cx, 130 ; Max chars to tolerate in a row
-
- RAP_err_2:
- call Get_char ; Try for another char
- jc RAP_empty ; Line is idle
-
- loop RAP_err_2 ; Eat another char
-
- RAP_empty:
- mov ah, ASCII_NAK ; That nasty character
- call OutChr ; Send it
- nop
- nop
- nop
-
- stc ; Flag an error
- ret ; Go home
-
- Receive_a_packet ENDP
-
-
- ; Send_a_packet -- Routine to assemble and send an XMODEM data packet
-
- Send_a_packet PROC
-
- call ClrBuf ; Flush any chars already received
-
- mov ah, SOH ; Start each packet with SOH
- call OutChr ; Send it along
- nop
- nop
- nop
-
- mov ah, BYTE PTR Pack.PktNum ; Copy packet number to ah
- call OutChr ; Send it along
- nop
- nop
- nop
-
- mov ah, 255 ; Funny packet number encoding
- sub ah, BYTE PTR Pack.PktNum ; One's complement
- call OutChr ; It too
- nop
- nop
- nop
-
- mov cx, 128 ; Number of chars to send
- mov si, Buffer_ptr ; Pick up current ptr
- mov Tally, 0 ; Clear counter
-
- SAP_Loop:
- lodsb ; Pick up the byte
- sub ah, ah ; Clear high half
- add Tally, ax ; Add in the new character
- mov ah, al ; Copy char to ah
- call OutChr ; Send it out
- nop
- nop
- nop
-
- loop SAP_Loop ; Do 128 characters
-
- mov ah, BYTE PTR Tally ; Use low order half of total as checksum
- call OutChr ; Send the checksum (remainder)
- nop
- nop
- nop
-
- ret ; Go home
-
- Send_a_packet ENDP
-
-
- Get_char PROC
-
- push cx ; Save cx reg
- mov Abort_flag, 0 ; Clear abort flag
- mov ah, 2Ch ; Code to Get Time
- int Dos ; Get it
-
- add dh, Timeout ; Add in the timeout time
- cmp dh, 59 ; Too many?
- jle GCH_doit
-
- sub dh, 60 ; Pull down the seconds
- inc cl ; Bump the minutes
-
- cmp cl, 59 ; Too many?
- jle GCH_doit ; No
-
- sub cl, 60 ; Pull down the minutes
- inc ch ; Bump the hours
-
- GCH_doit:
- mov HrMn, cx ; Save hours and minutes
- mov ScHn, dx ; Save seconds and hundredths
-
- GCH_Loop:
- cmp Count, 0 ; Any characters to read?
- jnz GCH_Got_char ; Found one
-
- mov dl, 0FFh ; Want input mode
- mov ah, DConIO ; Code for direct console input w/o echo
- int Dos ; Get a char if any is there
- jz GCH_No_keyboard ; User hasn't typed anything
-
- cmp al, 3 ; User type ^C?
- jne GCH_Not_Ctrl_C ; No
-
- mov Abort_flag, 0FFh ; Flag the abort
- call Say_Aborted ; Standard exit message for ^C
-
- jmp SHORT GCH_done ; Done here
-
- GCH_Not_Ctrl_C:
- or al, al ; Zero?
- jne GCH_Beep ; No
-
- int Dos ; Eat the second part of the funny char
-
- GCH_Beep:
- call Beep ; User hit wrong key, make a noise
-
- GCH_No_keyboard:
- call Carry_if_expired ; See if time has hit yet
- jnc GCH_loop ; Not yet
-
- jmp SHORT GCH_done ; Timeout
-
- GCH_Got_char:
- call PrtChr ; Pick up the character
- clc ; Got a character, clear error flag
-
- GCH_done:
- pop cx ; Restore cx reg
- ret ; Go home happy
-
- Get_char ENDP
-
-
- ; Jumping to this location is like retskp. It assumes the instruction
- ; after the call is a jmp addr
-
- RSKP PROC NEAR
- pop bp
- add bp,3
- push bp
- ; ret
- RSKP ENDP
-
- ; Jumping here is the same as a ret
-
- R PROC NEAR
- ret
- R ENDP
-
- Code ENDS
-
- END
-